package com.ly.heart.service.king;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import com.kingdee.bos.webapi.entity.IdentifyInfo;
import com.kingdee.bos.webapi.entity.RepoRet;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import com.ly.common.core.domain.entity.SysDept;
import com.ly.common.core.domain.entity.SysUser;
import com.ly.common.exception.CustomException;
import com.ly.common.utils.erp.CommonUtil;
import com.ly.common.utils.erp.KingConstUtil;
import com.ly.heart.domain.*;
import com.ly.heart.domain.king.BaseChildBo;
import com.ly.heart.domain.king.other.OtherDetailBo;
import com.ly.heart.domain.king.other.PayableOtherBo;
import com.ly.heart.domain.request.KingBaseSingleRequest;
import com.ly.heart.domain.response.KingBaseResponse;
import com.ly.heart.domain.response.KingBaseResponseError;
import com.ly.heart.domain.response.KingBaseResponseSuccessEntity;
import com.ly.heart.service.*;
import com.ly.heart.util.CurrentUserUtil;
import com.ly.heart.util.KingCommonUtil;
import com.ly.system.service.ISysDeptService;
import com.ly.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Component
@Slf4j
public class PayableOtherPushService {

    @Resource
    private IKingInvoicePayableOtherService iKingInvoicePayableOtherService;
    @Resource
    private IKingInvoicePayableReceivableOtherDetailService iKingInvoicePayableReceivableOtherDetailService;
    @Resource
    private ISupplierService iSupplierService;
    @Resource
    private ICustomerService iCustomerService;
    @Resource
    private ISysUserService iSysUserService;
    @Resource
    private ISysDeptService iSysDeptService;
    @Resource
    private IKingBaseTransactionsCompanyService iKingBaseTransactionsCompanyService;
    @Resource
    private IKingOrgService iKingOrgService;

    public void push ( KingInvoicePayableOtherEntity otherEntity ) {
        log.info ( "其他应付单调用金蝶下推 -> {}", otherEntity );
        KingOrgEntity orgEntity = iKingOrgService.getOne ( new LambdaQueryWrapper<KingOrgEntity> ().eq ( KingOrgEntity :: getOrgId, CurrentUserUtil.getCompanyId () ).eq ( KingOrgEntity :: getIsDisabled, true ) );
        if ( orgEntity == null ) {
            throw new CustomException ( "请先至系统管理中配置金蝶账套！" );
        }
        IdentifyInfo identifyInfo = KingCommonUtil.getIdentifyInfo ( orgEntity );
        K3CloudApi client = new K3CloudApi ( identifyInfo );
        KingInvoicePayableOtherEntity payableOtherEntity = iKingInvoicePayableOtherService.querySingleById ( otherEntity.getId () );
        if ( ObjectUtils.isEmpty ( payableOtherEntity ) ) {
            throw new CustomException ( "其他应付单对象为空" );
        }
        if ( payableOtherEntity.getIsSend () == KingConstUtil.KING_DATA_IS_SEND_YES ) {
            throw new CustomException ( "该单据已推送金蝶，无需重复推送！" );
        }
        PayableOtherBo bo = assembleOtherPayable ( payableOtherEntity );
        try {
            save ( bo, client );
            submit ( bo, client );
            audit ( bo, client );
            updateSendSuccess ( payableOtherEntity.getId () );
        } catch ( Exception e ) {
            e.printStackTrace ();
            throw new CustomException ( "推送失败，请检查后重试！" );
        }
    }

    /**
     * 推送其他应付单
     *
     * @param bo
     * @param client
     */
    private void save (PayableOtherBo bo, K3CloudApi client ) throws Exception {
        KingBaseSingleRequest singleRequest = new KingBaseSingleRequest ();
        singleRequest.setModel ( bo );
        String s = JSONObject.toJSONString ( singleRequest );
        log.info ( "其他应付单转JSON->{}", s );
        String resultJson = client.save ( KingConstUtil.AP_OtherPayable, s );
        Gson gson = new Gson ();
        //对返回结果进行解析和校验
        RepoRet repoRet = gson.fromJson ( resultJson, RepoRet.class );
        KingBaseResponse baseResponse = JSONObject.parseObject ( gson.toJson ( repoRet.getResult ().getResponseStatus () ), KingBaseResponse.class );
        StringBuilder sb = new StringBuilder ();
        if ( baseResponse.getIsSuccess () ) {
            List<KingBaseResponseSuccessEntity> successEntities = baseResponse.getSuccessEntitys ();
            sb.append ( "其他应付单-编码为：【" );
            successEntities.forEach ( success -> {
                sb.append ( success.getNumber () ).append ( ";" );
            } );
            sb.append ( "】" );
            log.info ( "{} 推送成功", sb );

        } else {
            List<KingBaseResponseError> errors = baseResponse.getErrors ();
            errors.forEach ( err -> {
                sb.append ( err.getMessage () ).append ( ";" );
            } );
            throw new RuntimeException ( "其他应付单-推送失败：【" + sb + "】" );
        }
    }

    /**
     * 提交到金蝶
     *
     * @param bo
     * @param client
     * @throws Exception
     */
    private void submit (PayableOtherBo bo, K3CloudApi client ) throws Exception {
        List<String> strings = new ArrayList<> ();
        strings.add ( bo.getFBillNo () );
        bo.setNumbers ( strings );
        String jsonData = JSON.toJSONString ( bo );
        String resultJson = client.submit ( KingConstUtil.AP_OtherPayable, jsonData );
        Gson gson = new Gson ();
        //对返回结果进行解析和校验
        RepoRet repoRet = gson.fromJson ( resultJson, RepoRet.class );
        KingBaseResponse baseResponse = JSONObject.parseObject ( gson.toJson ( repoRet.getResult ().getResponseStatus () ), KingBaseResponse.class );
        StringBuilder sb = new StringBuilder ();
        if ( baseResponse.getIsSuccess () ) {
            //提交成功
            List<KingBaseResponseSuccessEntity> successEntities = baseResponse.getSuccessEntitys ();
            sb.append ( "其他应付单-编码为：【" );
            successEntities.forEach ( success -> {
                sb.append ( success.getNumber () ).append ( ";" );
            } );
            sb.append ( "】" );
            log.error ( "{} 提交成功", sb );
        } else {
            List<KingBaseResponseError> errors = baseResponse.getErrors ();
            errors.forEach ( err -> {
                sb.append ( err.getMessage () ).append ( ";" );
            } );
            throw new RuntimeException ( "其他应付单-提交失败：【" + sb + "】" );
        }
    }

    /**
     * 审批其他应付单
     * @param bo
     * @param client
     * @throws Exception
     */
    private void audit (PayableOtherBo bo, K3CloudApi client ) throws Exception {
        List<String> strings = new ArrayList<> ();
        strings.add ( bo.getFBillNo () );
        bo.setNumbers ( strings );
        String jsonData = JSON.toJSONString ( bo );
        String resultJson = client.audit ( KingConstUtil.AP_OtherPayable, jsonData );
        Gson gson = new Gson ();
        //对返回结果进行解析和校验
        RepoRet repoRet = gson.fromJson ( resultJson, RepoRet.class );
        KingBaseResponse baseResponse = JSONObject.parseObject ( gson.toJson ( repoRet.getResult ().getResponseStatus () ), KingBaseResponse.class );
        StringBuilder sb = new StringBuilder ();
        if ( baseResponse.getIsSuccess () ) {
            //提交成功
            List<KingBaseResponseSuccessEntity> successEntities = baseResponse.getSuccessEntitys ();
            sb.append ( "其他应付单-编码为：【" );
            successEntities.forEach ( success -> {
                sb.append ( success.getNumber () ).append ( ";" );
            } );
            sb.append ( "】" );
            log.error ( "{} 审核成功", sb );
        } else {
            List<KingBaseResponseError> errors = baseResponse.getErrors ();
            errors.forEach ( err -> {
                sb.append ( err.getMessage () ).append ( ";" );
            } );
            throw new RuntimeException ( "其他应付单审核失败：【" + sb + "】" );
        }
    }

    private void updateSendSuccess (String id) {
        KingInvoicePayableOtherEntity payableOtherEntity = new KingInvoicePayableOtherEntity ();
        payableOtherEntity.setId ( id );
        payableOtherEntity.setIsSend ( KingConstUtil.KING_DATA_IS_SEND_YES );
        boolean b = iKingInvoicePayableOtherService.updateById ( payableOtherEntity );
        if ( ! b ) {
            throw new CustomException ( "修改推送金蝶状态失败！" );
        }
    }

    /**
     * 组装推送金额业务对象
     *
     * @param payableOtherEntity
     * @return
     */
    private PayableOtherBo assembleOtherPayable (KingInvoicePayableOtherEntity payableOtherEntity ) {
        PayableOtherBo bo = new PayableOtherBo ();
        //1.基本
        bo.setFBillNo ( payableOtherEntity.getDocNo () );
        BaseChildBo docType = new BaseChildBo ().setFNumber ( payableOtherEntity.getDocTypeCode () );
        bo.setFBillTypeID ( docType );
        //往来单位类型
        bo.setFCONTACTUNITTYPE ( payableOtherEntity.getTransactionCompanyType () );
        //结算组织
        BaseChildBo settleOrg = new BaseChildBo ().setFNumber ( payableOtherEntity.getSettleDeptCode () );
        bo.setFSETTLEORGID ( settleOrg );
        //往来单位，要根据往来单位类型去区分查询对象
        BaseChildBo tranctionDept = new BaseChildBo ();
        if ( payableOtherEntity.getTransactionCompanyType ().equals ( "BD_Supplier" ) ) {
            SupplierEntity supplierEntity = iSupplierService.getById ( payableOtherEntity.getTransactionCompanyId () );
            tranctionDept.setFNumber ( supplierEntity.getSupplierCode () );
        } else if ( payableOtherEntity.getTransactionCompanyType ().equals ( "BD_Customer" ) ) {
            CustomerEntity customerEntity = iCustomerService.getById ( payableOtherEntity.getTransactionCompanyId () );
            tranctionDept.setFNumber ( customerEntity.getCustomerCode () );
        } else if ( payableOtherEntity.getTransactionCompanyType ().equals ( "BD_Empinfo" ) ) {
            SysUser userEntity = iSysUserService.getById ( payableOtherEntity.getTransactionCompanyId () );
            tranctionDept.setFNumber ( userEntity.getUserCode () );
        } else if ( payableOtherEntity.getTransactionCompanyType ().equals ( "BD_Department" ) ) {
            SysDept dept = iSysDeptService.getById ( payableOtherEntity.getTransactionCompanyId () );
            tranctionDept.setFNumber ( dept.getDeptCode () );
        } else if ( payableOtherEntity.getTransactionCompanyType ().equals ( "FIN_OTHERS" ) ) {
            KingBaseTransactionsCompanyEntity transactionsCompanyEntity = iKingBaseTransactionsCompanyService.getById ( payableOtherEntity.getTransactionCompanyId () );
            tranctionDept.setFNumber ( transactionsCompanyEntity.getCompanyCode () );
        }
        bo.setFCONTACTUNIT(tranctionDept);
        //付款组织
        BaseChildBo payDept = new BaseChildBo ().setFNumber ( payableOtherEntity.getPayDeptCode () );
        bo.setFPAYORGID ( payDept );
        //业务日期
        bo.setFDATE ( CommonUtil.getDateStrFormat ( payableOtherEntity.getBizTime (), "yyyy-MM-dd HH:mm:ss" ) );
        //币别
        BaseChildBo currency = new BaseChildBo ().setFNumber ( payableOtherEntity.getKingBaseCurrencyCode () );
        bo.setFCURRENCYID ( currency );
        //采购组织
        //BaseChildBo procureDept = new BaseChildBo ().setFNumber ( payableOtherEntity.getProductDeptCode () );
        //bo.setFPURCHASEORGID ( procureDept );
        //到期日
        bo.setFENDDATE_H ( CommonUtil.getDateStrFormat ( payableOtherEntity.getDueTime (), "yyyy-MM-dd HH:mm:ss" ) );
        //总金额
        bo.setFTOTALAMOUNTFOR_H ( payableOtherEntity.getTotalAmount () );
        //采购部门
        //BaseChildBo proDept = new BaseChildBo ().setFNumber ( payableOtherEntity.getProDeptCode () );
        //bo.setFPURCHASEDEPTID ( proDept );
        //未借款金额
        bo.setFNOTSETTLEAMOUNTFOR ( payableOtherEntity.getNoLoanAmount () );
        //申请部门
        BaseChildBo apply = new BaseChildBo ().setFNumber ( payableOtherEntity.getApplyDeptCode () );
        bo.setFDEPARTMENTID ( apply );
        //采购员
        BaseChildBo procureUser = new BaseChildBo ().setFNumber ( payableOtherEntity.getProcureUserCode () );
        bo.setFPURCHASERID ( procureUser );
        //备注
        bo.setFRemarks ( payableOtherEntity.getRemarks () );

        //财务模块：结算方式
        BaseChildBo settleType = new BaseChildBo ().setFNumber ( payableOtherEntity.getSettlementTypeCode () );
        bo.setFSettleTypeID ( settleType );
        //财务模块：付款条件
        BaseChildBo payCondition = new BaseChildBo ().setFNumber ( payableOtherEntity.getPayConditionCode () );
        bo.setFPayConditon ( payCondition );
        //财务模块：到期日计算日期
        bo.setFACCNTTIMEJUDGETIME ( CommonUtil.getDateStrFormat ( payableOtherEntity.getDueClaTime (), "yyyy-MM-dd HH:mm:ss" ) );

        //2.其他应付单的明细
        List<OtherDetailBo> otherDetailBos = assembleOtherPayableDetail ( payableOtherEntity.getId () );
        bo.setFEntity ( otherDetailBos );
        return bo;
    }

    /**
     * 组装其他应付单的明细行
     *
     * @param otherPayableId
     * @return
     */
    private List<OtherDetailBo> assembleOtherPayableDetail ( String otherPayableId ) {
        List<OtherDetailBo> otherDetailBos = new ArrayList<> ();
        List<KingInvoicePayableReceivableOtherDetailEntity> list = iKingInvoicePayableReceivableOtherDetailService.list ( new QueryWrapper<KingInvoicePayableReceivableOtherDetailEntity> ().
                eq ( "relation_other_id", otherPayableId ) );
        list.forEach ( detail -> {
            OtherDetailBo bo = new OtherDetailBo ();
            //费用项目编码
            BaseChildBo feeCode = new BaseChildBo ().setFNumber ( detail.getFeeCode () );
            bo.setFCOSTID ( feeCode );
            //费用承担部门
            BaseChildBo feeBearCode = new BaseChildBo ().setFNumber ( detail.getFeeBearDeptCode () );
            bo.setFCOSTDEPARTMENTID ( feeBearCode );
            //发票类型
            bo.setFINVOICETYPE ( detail.getInvoiceType () );
            //税率
            bo.setFEntryTaxRate ( detail.getTaxRate () );
            //不含税金额
            bo.setFNOTAXAMOUNTFOR ( detail.getNoTaxAmount () );
            //税额
            bo.setFTAXAMOUNTFOR ( detail.getTaxAmount () );
            //其他应付单的总金额
            bo.setFTOTALAMOUNTFOR ( detail.getTotalAmount () );
            //其他应付单的未借款金额
            bo.setFNOTSETTLEAMOUNTFOR_D ( detail.getNoLoanAmount () );
            //备注
            bo.setFCOMMENT ( detail.getRemarks () );
            //源单类型
            //bo.setFSOURCETYPE ( detail.getSourceDocType () );

            //源单编号
            bo.setFSourceBillNo ( detail.getSourceDocNo () );
            otherDetailBos.add ( bo );
        } );
        return otherDetailBos;
    }

}
